#!/bin/bash

# 作者: 无涯有涯
# 用法： curl -sSL "https://gitee.com/veryx/galaxy-tools/raw/master/8-iotest/kdgalaxy_io_test.sh" | bash

red="\e[31m"
green="\e[32m"
yellow="\e[33m"

none="\e[0m"

TEST_DIR=$(pwd)
FILE_SIZE="5120m"
OUTPUT_FILE="${TEST_DIR}/kdgalaxy_io_test.log"

echo -e "脚本版本: ${green}2025-11-20${none}"
# echo -e "发布地址: ${yellow}https://vip.kingdee.com/link/s/ZbZL3${none} 请关注并使用最新版本, 以获取最佳测试结果.\n"

# 解析fio测试结果
extract_metrics() {
    local logfile="$1"
    local section="$2"
    local rw_type="$3"
    
    # 提取整个测试部分
    section_content=$(awk "/^${section}:/,/^$/" $logfile)
    
    # 提取IOPS
    iops=$(echo "$section_content" | grep -E "IOPS=" | grep -oE "IOPS=[0-9.kK]+" | cut -d= -f2 | head -1)
    
    # 提取带宽
    bw=$(echo "$section_content" | grep -E "BW=" | grep -oE "BW=[0-9.]+[KM]?i?B/s" | cut -d= -f2 | head -1)
    
    # 提取延迟
    lat_line=$(echo "$section_content" | grep -A 5 "lat.*avg" | grep "avg=")
    lat_value=$(echo "$lat_line" | grep -oE "avg=[0-9.]+" | cut -d= -f2 | head -1)
    lat_unit=$(echo "$lat_line" | grep -oE "[uunm]?sec" | head -1)
    
    # 格式化输出
    if [[ -n "$iops" && -n "$bw" ]]; then
        printf "  %-6s | IOPS: %7s | 带宽: %9s | 延迟: %6.2f %s\n" \
               "$rw_type" "$iops" "$bw" "$lat_value" "$lat_unit"
    else
        echo "  $rw_type 测试结果解析失败，请查看完整报告"
    fi
}

# 检查依赖工具
check_fio() {
    if ! command -v fio &> /dev/null; then
        if command -v apt &> /dev/null; then
            echo -e "${red}错误${none}: 需要先安装fio工具, 请尝试执行: ${yellow}sudo apt install fio${none} 后重试."
        elif command -v dnf &> /dev/null; then
            echo -e "${red}错误${none}: 需要先安装fio工具, 请尝试执行: ${yellow}sudo dnf install fio${none} 后重试."
        elif command -v yum &> /dev/null; then
            echo -e "${red}错误${none}: 需要先安装fio工具, 请尝试执行: ${yellow}sudo yum install fio${none} 后重试."
        else
            echo -e "${red}错误${none}: 需要先安装fio工具, 请手动安装后重试."
        fi
        exit 1
    fi
}

# 检查磁盘空间
check_disk_space() {
    local needs=$(( ${FILE_SIZE/m} * 2 * 1024 * 1024 ))
    local total=$(df -B1 . | awk 'NR==2{print $2}')
    local avail=$(df -B1 . | awk 'NR==2{print $4}')
    
    if (( avail - needs <= total * 20 / 100 )); then
        echo -e "${red}错误${none}: 磁盘空间不足，为安全起见不允许进行测试！"
        exit 1
    fi
}

# 确认测试目录
confirm_test_dir() {
    echo -e "本脚本基于当前目录, 对其所在磁盘进行性能测试."
    echo -e "当前目录: ${yellow}${TEST_DIR}${none}"
    echo -e "请您确认: 目录是否${green}正确${none}? 如目录${red}错误${none}, 请将${yellow}脚本移动到待测试目录后重新运行${none}."
    read -p "确认继续? [y/N]: " confirm < /dev/tty

    if [[ "${confirm,,}" != "y" ]]; then
        echo "测试已取消!"
        exit 0
    fi
}

# 正式测试流程
check_fio
check_disk_space
confirm_test_dir
# 输出机器信息
echo
echo "机器信息:"
echo "=============================================================="
hostnamectl
echo "=============================================================="

# 显示存储设备信息
echo "分区信息:"
echo "=============================================================="
df -Th -x tmpfs -x devtmpfs -x efivarfs -x overlay
echo "=============================================================="

# fio结果临时文件
fio_tmplog=$(mktemp)
# fio配置临时文件
fio_tmpcfg=$(mktemp)
# fio配置文件内容
cat << EOF | sed -e 's/#.*//; s/[[:space:]]*=[[:space:]]*/=/g; /^$/d' > $fio_tmpcfg
[global]
bs          = 8k            # 块大小
size        = $FILE_SIZE    # 测试文件大小
fsync       = 0             # 异步写入
direct      = 1             # 禁止页缓存
thread      = 1             # 使用线程创建任务，当 numjobs > 1 时创建线程。
unlink      = 1             # 删除测试文件
runtime     = 30            # 每个作业运行时间（秒）
numjobs     = 8             # 并发数
iodepth     = 1             # IO深度,psync限制为1
ioengine    = psync         # IO引擎,使用同步引擎
pre_read    = 0             # 禁止预读文件
disk_util   = 1             # 报告磁盘使用情况
invalidate  = 1             # 清理缓存，保障读取性能测试准确性。
create_fsync = 1            # 初始化数据强制写入磁盘，以便准确测试读取性能。
time_based                  # 强制测试运行满指定的时间​​，搭配 runtime 使用。
refill_buffers              # 重新填充缓冲区，随机写时使用新的数据。
group_reporting             # 汇总报告

# 随机读测试
[rand_read]
rw       = randread         # 随机读
name     = rand_read        # 测试名称
filename = rand_read.dat    # 测试文件
stonewall                   # 顺序执行
new_group                   # 创建新的组
wait_for_previous           # 等待上一个测试完成

# 随机写测试
[rand_write]
rw       = randwrite
name     = rand_write
filename = rand_write.dat
stonewall
new_group
wait_for_previous
EOF

# 开始测试
echo -ne "${green}测试中...${none}"
fio --output=$fio_tmplog $fio_tmpcfg >/dev/null 2>&1

echo -e "\r\033[K测试结果摘要:"
echo "=============================================================="
extract_metrics $fio_tmplog "rand_read"  "读取"
extract_metrics $fio_tmplog "rand_write" "写入"
echo "=============================================================="

# 日志输出
{
    echo -e "测试日期: $(date)"
    echo =================================================================================================================
    echo -e "测试目录: ${TEST_DIR}"
    echo =================================================================================================================
    echo -e "主机信息:"
    hostnamectl
    echo =================================================================================================================
    echo -e "分区信息:"
    df -Th -x tmpfs -x devtmpfs -x efivarfs -x overlay
    echo =================================================================================================================
    echo -e "测试结果:"
    cat $fio_tmplog
} > $OUTPUT_FILE

echo -e "${green}完整报告: ${OUTPUT_FILE}${none}\n"

# 清理临时文件
rm -f $fio_tmplog $fio_tmpcfg rand_read.dat rand_write.dat
